//
// Created by Scave on 2025/9/20.
//

#ifndef TIEC_TREE_UTIL_H
#define TIEC_TREE_UTIL_H

#include "component.h"
#include "macro.h"
#include "tree.h"

namespace NS_TIEC {
  class FullNamePrinter : TreeVisitor<void, std::wstringstream&> {
  public:
    WString printFullName(const PTR<ExpressionTree>& expr);

    void visitFieldAccessTree(const PTR<FieldAccessTree>& tree, std::wstringstream& param) override;
    void visitIdentifierTree(const PTR<IdentifierTree>& tree, std::wstringstream& param) override;
  };

  class ConstantResolver : TreeVisitor<ConstValue, NullValue&> {
  public:
    ConstValue resolveConstant(const PTR<ExpressionTree>& tree);

    ConstValue visitFieldAccessTree(const PTR<FieldAccessTree>& tree, NullValue& param) override;
    ConstValue visitIdentifierTree(const PTR<IdentifierTree>& tree, NullValue& param) override;
    ConstValue visitLiteralTree(const PTR<LiteralTree>& tree, NullValue& param) override;
  };

  class FindTreeBySymbol : TreeVisitor<PTR<Tree>, const PTR<Symbol>&> {
  public:
    PAIR<PTR<CompilationUnitTree>, PTR<Tree>> findInTreeTable(const PTR<TreeTable>& tree_tab, const PTR<Symbol>& symbol);

    PTR<Tree> visitCompilationUnitTree(const PTR<CompilationUnitTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitClassTree(const PTR<ClassTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitVariableTree(const PTR<VariableTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitMethodTree(const PTR<MethodTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitEventTree(const PTR<EventTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitIdentifierTree(const PTR<IdentifierTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitBlockTree(const PTR<BlockTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitIfTree(const PTR<IfTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitSwitchTree(const PTR<SwitchTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitCaseTree(const PTR<CaseTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitForLoopTree(const PTR<ForLoopTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitForEachTree(const PTR<ForEachTree>& tree, const PTR<Symbol>& param) override;
    PTR<Tree> visitWhileLoopTree(const PTR<WhileLoopTree>& tree, const PTR<Symbol>& param) override;
  };

  class FindTreesByAnnotation : TreeVisitor<void, const PTR<Name>&> {
  public:
    List<PTR<AnnotatedTree>> findInContext(const PTR<Context>& context, const PTR<Name>& name);

    void visitCompilationUnitTree(const PTR<CompilationUnitTree>& tree, const PTR<Name>& name) override;
    void visitClassTree(const PTR<ClassTree>& tree, const PTR<Name>& name) override;
    void visitVariableTree(const PTR<VariableTree>& tree, const PTR<Name>& name) override;
    void visitMethodTree(const PTR<MethodTree>& tree, const PTR<Name>& name) override;
    void visitEventTree(const PTR<EventTree>& tree, const PTR<Name>& name) override;
    void visitBlockTree(const PTR<BlockTree>& tree, const PTR<Name>& name) override;
    void visitIfTree(const PTR<IfTree>& tree, const PTR<Name>& name) override;
    void visitSwitchTree(const PTR<SwitchTree>& tree, const PTR<Name>& name) override;
    void visitCaseTree(const PTR<CaseTree>& tree, const PTR<Name>& name) override;
    void visitForLoopTree(const PTR<ForLoopTree>& tree, const PTR<Name>& name) override;
    void visitForEachTree(const PTR<ForEachTree>& tree, const PTR<Name>& name) override;
    void visitWhileLoopTree(const PTR<WhileLoopTree>& tree, const PTR<Name>& name) override;
  private:
    WPTR<NameTable> names_;
    List<PTR<AnnotatedTree>> result_;
    bool hasAnnotation(const PTR<AnnotatedTree>& tree, const PTR<Name>& name) const;
  };

  class FindSymbolsByAnnotation : TreeVisitor<void, const PTR<Name>&> {
  public:
    List<PTR<Symbol>> findInContext(const PTR<Context>& context, const PTR<Name>& name);

    void visitCompilationUnitTree(const PTR<CompilationUnitTree>& tree, const PTR<Name>& name) override;
    void visitClassTree(const PTR<ClassTree>& tree, const PTR<Name>& name) override;
    void visitVariableTree(const PTR<VariableTree>& tree, const PTR<Name>& name) override;
    void visitMethodTree(const PTR<MethodTree>& tree, const PTR<Name>& name) override;
    void visitEventTree(const PTR<EventTree>& tree, const PTR<Name>& name) override;
    void visitBlockTree(const PTR<BlockTree>& tree, const PTR<Name>& name) override;
    void visitIfTree(const PTR<IfTree>& tree, const PTR<Name>& name) override;
    void visitSwitchTree(const PTR<SwitchTree>& tree, const PTR<Name>& name) override;
    void visitCaseTree(const PTR<CaseTree>& tree, const PTR<Name>& name) override;
    void visitForLoopTree(const PTR<ForLoopTree>& tree, const PTR<Name>& name) override;
    void visitForEachTree(const PTR<ForEachTree>& tree, const PTR<Name>& name) override;
    void visitWhileLoopTree(const PTR<WhileLoopTree>& tree, const PTR<Name>& name) override;
  private:
    WPTR<NameTable> names_;
    List<PTR<Symbol>> result_;
    bool hasAnnotation(const PTR<AnnotatedTree>& tree, const PTR<Name>& name) const;
  };

  class TreeUtil {
  public:
    /// 将表达式转换为名称
    /// @param context 当前编译器上下文
    /// @param expr 表达式
    /// @return 如果不是名称表达式，则返回null
    static PTR<Name> printFullName(const PTR<Context>& context, const PTR<ExpressionTree>& expr);

    /// 将表达式转换为名称
    /// @param names 当前编译器上下文中的名称表
    /// @param expr 表达式
    /// @return 如果不是名称表达式，则返回null
    static PTR<Name> printFullName(const PTR<NameTable>& names, const PTR<ExpressionTree>& expr);

    /// 将类名分割为包名和类名的键值对
    /// @param names 当前编译器上下文中的名称表
    /// @param full_name 完整类名
    static PAIR<PTR<Name>, PTR<Name>> splitClassName(const PTR<NameTable>& names, const PTR<Name>& full_name);

    /// 取全名称尾部名称作为单名称
    /// @param names 当前编译器上下文中的名称表
    /// @param full_name 全名称
    static PTR<Name> getSimpleName(const PTR<NameTable>& names, const PTR<Name>& full_name);

    /// 消解常量，如果表达式指向的是一个常量定义那么就返回其引用的常量值
    /// @param expr 表达式
    /// @return 常量值，如果表达式不指向常量则返回 ConstValue::kNull
    static ConstValue resolveConstant(const PTR<ExpressionTree>& expr);

    /// 获取被注解成员的Symbol
    /// @param annotated 被注解成员，如类、方法、变量等
    static PTR<Symbol> getSymbolFromAnnotated(const PTR<AnnotatedTree>& annotated);

    /// 获取被注解成员的Symbol并强转为指定类型
    /// @tparam T Symbol的派生类型
    /// @param annotated 被注解成员，如类、方法、变量等
    template<typename T>
    static PTR<T> getSymbolFromAnnotatedAs(const PTR<AnnotatedTree>& annotated) {
      return std::static_pointer_cast<T>(getSymbolFromAnnotated(annotated));
    }
  private:
    static FullNamePrinter* name_printer_;
    static ConstantResolver* const_resolver_;
  };

  class TreeMessageEmitter {
  public:
    explicit TreeMessageEmitter(const PTR<Context>& context);

    /// 报告一个语法树警告
    /// @param tree 语法树，用于标记警告范围
    /// @param key message key
    /// @param ... 格式化参数
    void warnAt(const PTR<Tree>& tree, const char* key, ...) const;

    /// 报告一个语法树错误
    /// @param tree 语法树，用于标记错误范围
    /// @param key message key
    /// @param ... 格式化参数
    void errorAt(const PTR<Tree>& tree, const char* key, ...) const;

    /// 报告一个编译器错误的静态方法，避免每次都要新建TreeMessageEmitter对象
    /// @param context 编译器所处上下文
    /// @param at 错误的Tree
    /// @param key message key
    /// @param ... 格式化 参数
    static void reportError(const PTR<Context>& context, const PTR<Tree>& at, const char* key, ...);

    /// 报告一个编译器警告的静态方法，避免每次都要新建TreeMessageEmitter对象
    /// @param context 编译器所处上下文
    /// @param at 要警告的Tree
    /// @param key message key
    /// @param ... 格式化 参数
    static void reportWarning(const PTR<Context>& context, const PTR<Tree>& at, const char* key, ...);
  private:
    PTR<Messages> messages_;
    PTR<SourceManager> source_manager_;
  };

}

#endif //TIEC_TREE_UTIL_H